package cn.woochen.comlib

import android.content.Context
import android.os.Bundle
import android.util.Log
import android.view.*
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentTransaction
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import cn.woochen.comlib.config.IBaseView
import cn.woochen.comlib.loadinglayout.EmptyCallBack
import cn.woochen.comlib.loadinglayout.ErrorCallback
import cn.woochen.comlib.loadinglayout.LoadingHasContentCallBack
import cn.woochen.comlib.util.ComlibLog
import com.kingja.loadsir.core.LoadService
import com.kingja.loadsir.core.LoadSir
import kotlinx.coroutines.launch
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type

abstract class BaseLibraryDialogFragment<DB : ViewDataBinding, VM : BaseViewModel> :
    DialogFragment(), IBaseView {

    protected val mContext by lazy {
        requireActivity()
    }

    protected lateinit var mBinding: DB
        private set

    protected lateinit var mViewModel: VM

    protected lateinit var loadService: LoadService<*>

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        dialog?.window?.let {
            it.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setStyle(STYLE_NO_TITLE, R.style.dialog)
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        mBinding = DataBindingUtil.inflate(inflater, setContentView(), container, false)
        mViewModel = createViewModel()
        loadService = LoadSir.getDefault().register(mBinding.root)
        registerNecessaryObserver()
        initListener()
        initData()
        return loadService.loadLayout
    }

    private fun createViewModel(): VM {
        return ViewModelProvider(this).get(getVmClazz(this))
    }

    /**
     * 显示弹窗
     */
    fun show(context: Context) {
        val tag = javaClass.simpleName
        var manager: FragmentManager? = null
        if (context is AppCompatActivity) {
            manager = context.supportFragmentManager
        }
        if (manager != null && !manager.isDestroyed) {
            show(manager, tag)
        }
    }

    /**
     * 获取任意对象的泛型信息，返回一个继承了BaseViewModel的字节码对象
     */
    private fun getVmClazz(obj: Any): Class<VM> {
        var cls: Class<*>? = obj.javaClass
        var vmClass: Class<VM>? = null
        while (vmClass == null && cls != null) {
            vmClass = getVMClass(cls)
            cls = cls.superclass
        }
        if (vmClass == null) {
            vmClass = BaseViewModel::class.java as Class<VM>
        }
        return vmClass
    }

    private fun getVMClass(cls: Class<*>): Class<VM>? {
        val type: Type? = cls.genericSuperclass
        if (type is ParameterizedType) {
            val types: Array<Type> = type.actualTypeArguments
            for (t in types) {
                if (t is Class<*>) {
                    if (BaseViewModel::class.java.isAssignableFrom(t)) {
                        return t as Class<VM>
                    }
                } else if (t is ParameterizedType) {
                    val rawType: Type = t.rawType
                    if (rawType is Class<*>) {
                        if (BaseViewModel::class.java.isAssignableFrom(rawType)) {
                            return rawType as Class<VM>
                        }
                    }
                }
            }
        }
        return null
    }

    protected abstract fun setContentView(): Int

    protected open fun initListener() {}

    /**
     * 网络请求数据
     */
    protected open fun requestData() {}

    protected abstract fun initData()

    override fun showContent() {
        loadService.showSuccess()
    }

    override fun showEmpty() {
        loadService.showCallback(EmptyCallBack::class.java)
    }

    override fun showLoading(content: String) {
        loadService.showCallback(LoadingHasContentCallBack::class.java)
    }

    override fun showError() {
        loadService.showCallback(ErrorCallback::class.java)
    }

    /**
     * 注册 UI 事件
     */
    protected open fun registerNecessaryObserver() {
        lifecycleScope.launch {
            mViewModel.loadingChange.showDialog.collect {
                showLoading(it)
            }
        }
        lifecycleScope.launch {
            mViewModel.loadingChange.dismissDialog.collect {
                showContent()
            }
        }
    }

    /**
     * 解决Can not perform this action after onSaveInstanceState问题
     */
    override fun show(manager: FragmentManager, tag: String?) {
        try {
            val ft: FragmentTransaction = manager.beginTransaction()
            ft.add(this, tag)
            ft.commit()
        } catch (e: IllegalStateException) {
            ComlibLog.logcom("${javaClass.simpleName}:${e}")
        }
    }

}